package com.taotao.complier.calcu.visit;

import com.taotao.complier.calcu.ast.AddSubNode;
import com.taotao.complier.calcu.ast.AstNode;
import com.taotao.complier.calcu.ast.Expr2Node;
import com.taotao.complier.calcu.ast.ExprNode;
import com.taotao.complier.calcu.ast.FactorNode;
import com.taotao.complier.calcu.ast.MulDivNode;
import com.taotao.complier.calcu.ast.NumNode;
import com.taotao.complier.calcu.ast.Term2Node;
import com.taotao.complier.calcu.ast.TermNode;
import com.taotao.complier.calcu.lex.WordType;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;


/**
 * 求计算结果
 */
public class CalcuVisitor implements Visitor {

    /*
     *
     * 产生式
     *
     * 0: expr -> term  expr2
     * 1: expr2 ->  ADD_SUB term  expr2
     * 2:          | ε
     * 3: term ->  factor  term2
     * 4: term2 ->  MUL_DIV factor term2
     * 5:         | ε
     * 6: factor -> num
     * 7: MUL_DIV -> + | -
     * 8: ADD_SUB -> * | /
     *
     * 结合语法树结构和产生式来看：
     *      1.term和expr是完整的计算式,是可以算结果的,expr2与term2不是完整的计算式不能算结果;
     *      2.term是乘除，优先级高，应先算term结果再算expr结果（语法树的形状+后序遍历 已经满足这个顺序）
     *
     * 实现方案：其实就是递归求树中各个term和expr节点的结果，然后取根节点结果就是整个计算式结果
     *
     *
     */


    private AstNode root;


    private Map<AstNode, Integer> nodeResultMap = new HashMap<>();


    public CalcuVisitor(AstNode root) {
        this.root = root;
    }

    @Override
    public void visitNum(NumNode node) {
        nodeResultMap.put(node, Integer.parseInt(node.getToken().getVal()));
    }

    @Override
    public void visitMulDiv(MulDivNode node) {

    }

    @Override
    public void visitAddSub(AddSubNode node) {

    }

    @Override
    public void visitExpr(ExprNode exprNode) {
        Integer r = nodeResultMap.get(exprNode.getTerm());

        Expr2Node e2 = exprNode.getExpr2();
        while (null != e2) {
            // 取term计算结果
            Integer tr = nodeResultMap.get(e2.getTerm());

            if (Objects.equals(e2.getAddSub().getToken().getWordType(), WordType.ADD)) {
                r = r + tr;
            } else {
                r = r - tr;
            }
            e2 = e2.getExpr2();
        }

        nodeResultMap.put(exprNode, r);

    }

    @Override
    public void visitTerm(TermNode termNode) {
        Integer r = nodeResultMap.get(termNode.getFactor());

        Term2Node t2 = termNode.getTerm2();
        while (null != t2) {
            Integer t2r = nodeResultMap.get(t2.getFactor());

            if (Objects.equals(t2.getMulDiv().getToken().getWordType(), WordType.MUL)) {
                r = r * t2r;
            } else {
                r = r / t2r;
            }

            t2 = t2.getTerm2();

        }

        nodeResultMap.put(termNode, r);
    }

    @Override
    public void visitTerm2(Term2Node term2Node) {

    }

    @Override
    public void visitExpr2(Expr2Node expr2Node) {

    }

    @Override
    public void visitFactor(FactorNode fatorNode) {
        nodeResultMap.put(fatorNode, nodeResultMap.get(fatorNode.getNum()));
    }


    /**
     * 获取计算结果
     *
     * @return
     */
    public int getCalcuResult() {
        return nodeResultMap.get(root);
    }
}
